package com.mikeli.javacourse.lesson4;

import com.sun.xml.internal.ws.util.CompletedFuture;

import java.util.Arrays;
import java.util.concurrent.*;
import java.util.concurrent.locks.*;
import java.util.stream.Collectors;

/**
 * 本周作业：（必做）思考有多少种方式，在main函数启动一个新线程或线程池，
 * 异步运行一个方法，拿到这个方法的返回值后，退出主线程？
 * 写出你的方法，越多越好，提交到github。
 * <p>
 * 一个简单的代码参考：
 */
public class Homework03 {
    private static ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
    static CountDownLatch lock = new CountDownLatch(1);
    static ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
    static ReentrantLock reentrantLock = new ReentrantLock();


    // 1
    private static volatile int result1 = 0;

    public static void main(String[] args) throws ExecutionException, InterruptedException, BrokenBarrierException {
        //第一种
        Future<Integer> result = executorService.submit(() -> fibo(36));
        System.out.println("第一种异步获取结果->" + result.get());
        reset();
        //第二种
        System.out.println("第二种异步获取结果->" + Arrays.asList(36).stream().parallel().map((v) -> fibo(v)).collect(Collectors.toList()).get(0));
        reset();
        //第三种
        executorService.execute(() -> {
            try {
                result1 = fibo(36);
            } finally {
                lock.countDown();
            }
        });
        lock.await();
        System.out.println("第三种异步获取结果->" + result1);
        reset();
        //第四种

        executorService.execute(() -> {
            try {
                reentrantLock.lock();
                result1 = fibo(36);
            } finally {
                reentrantLock.unlock();
            }
        });
        while (result1 == 0) ;
        System.out.println("第四种异步获取结果->" + result1);
        reset();
        //第五种
        Thread t1 = new Thread(() -> result1 = fibo(36));
        t1.start();
        t1.join();
        System.out.println("第五种异步获取结果->" + result1);
        reset();
        //第六种
        Thread six = new Thread(() -> {
            result1 = fibo(36);
            LockSupport.park();
        });
        executorService.submit(six);
        while (result1 == 0) ;
        LockSupport.unpark(six);
        System.out.println("第六种异步获取结果->" + result1);
        reset();
        Semaphore semaphore = new Semaphore(2);
        semaphore.acquire();
        new Thread(() -> {
            result1 = fibo(36);
            semaphore.release();
        }).start();
        while (semaphore.availablePermits() == 1) ;
        System.out.println("第七种异步获取结果->" + result1);
        reset();
        //第八种
        CyclicBarrier cyclicBarrier = new CyclicBarrier(2);
        executorService.submit(() -> {
            result1 = fibo(36);
            try {
                cyclicBarrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        });
        cyclicBarrier.await();
        System.out.println("第八种异步获取结果->" + result1);
        reset();
        //第九种
        result1 = CompletableFuture.supplyAsync(() -> fibo(36), executorService).get();
        System.out.println("第九种异步获取结果->" + result1);
        reset();
        //第十种
        final Condition condition = reentrantLock.newCondition();
        new Thread(() -> {
            try {
                reentrantLock.lock();
                result1 = fibo(36);
                condition.signal();
            } finally {
                reentrantLock.unlock();
            }

        }).start();
        reentrantLock.lock();
        condition.await();
        reentrantLock.unlock();
        System.out.println("第十种异步获取结果->" + result1);
        if(!executorService.awaitTermination(1000, TimeUnit.MILLISECONDS)){
            executorService.shutdownNow();
        };
    }

    private static int fibo(int a) {
        if (a < 2)
            return 1;
        return fibo(a - 1) + fibo(a - 2);
    }

    private static void reset() {
        result1 = 0;
    }

}
